package com.coder.rental.controller;

import cn.hutool.core.convert.NumberWithFormat;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWTPayload;
import com.coder.rental.entity.Permission;
import com.coder.rental.entity.User;
import com.coder.rental.security.CustomerAuthenticationException;
import com.coder.rental.service.IUserService;
import com.coder.rental.utils.JwtUtils;
import com.coder.rental.utils.RedisUtils;
import com.coder.rental.utils.Result;
import com.coder.rental.utils.RouteTreeUtils;
import com.coder.rental.vo.RouteVo;
import com.coder.rental.vo.TokenVo;
import com.coder.rental.vo.UserInfoVo;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author: zhanglin
 * @description:  权限控制器，token刷新
 * @date 2025/3/29
 */
@RestController
@RequestMapping("/rental/auth/")
public class AuthController {

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private IUserService iUserService;
    //刷新token请求
    @PostMapping("/refreshToken")
    public Result refreshToken(HttpServletRequest request){
        //01-获取token，因为请求中携带token，在请求头中获取token
        String token = request.getHeader("token");
        if(StrUtil.isEmpty(token)){
            token=request.getParameter("token");
        }
        //02-在VerifyTokenFilter中验证token后进行认证了，存在SecurityContextHolder上下文中，从它取出Authentication
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //03-从Authentication中取出用户信息
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        //04-解析token获取用户名
        String username = JwtUtils.parseToken(token).getClaim("username").toString();
        /*
        * 05-判断请求头的token的username和认证userDetails中的用户名是否相等,
        * 如果相等则重新生成token，以达到对token的有效期进行重新设置
        * */
        String newToken = "";
        if(StrUtil.equals(username, userDetails.getUsername())){
            Map<String,Object> map = new HashMap<>();
            map.put("username", userDetails.getUsername());
            newToken = JwtUtils.createToken(map);
        }else {
            throw new CustomerAuthenticationException("token数据异常");
        }
        //06-获取新token的过期时间
        NumberWithFormat claim = (NumberWithFormat) JwtUtils.parseToken(newToken).getClaim(JWTPayload.EXPIRES_AT);
        //07-利用convert对jwt载荷中的过期时间转换为DateTime类型，因为jwt中的过期时间是时间戳
        DateTime dateTime = (DateTime) claim.convert(DateTime.class, claim);
        long expireTime = dateTime.getTime();//得到的是毫秒级
        //08-创建tokenvo对象，将新生成的token和过期时间存入
        TokenVo tokenVo = new TokenVo();
        tokenVo.setToken(newToken).setExpireTime(expireTime);
        //09-将原有的token清除
        redisUtils.del("token:"+token);
        //10-将新的token存入redis
        long nowTime = DateTime.now().getTime();
        String newTokenKey = "token:"+newToken;
        redisUtils.set(newTokenKey, newToken, (expireTime-nowTime)/1000);
        return Result.success(tokenVo).setMessage("刷新token成功");
    }
    //获取用户信息请求
    @GetMapping("/info")
    public Result getUserInfo(){
        /*
        * 用户信息从哪来？
        * 在VerifyTokenFilter中验证token通过后，会封装authenticationToken认证令牌，
        * 并存入SecurityContextHolder中，从SecurityContextHolder上下文中获取认证信息
        * */
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication==null){
            return Result.fail().setMessage("认证信息为空");
        }
        //从authentication获取用户信息
        User user = (User) authentication.getPrincipal();
        
        //查询用户角色,filter(Objects::nonNull)过滤对象中的null值，map(Permission::getPermissionCode)对过滤后的每个权限对象调用getPermissionCode方法，查找角色
        // Object[] array = user.getPermissionList().stream().filter(Objects::nonNull)
        //         .map(Permission::getPermissionCode).toArray();
        
        List<String> list = iUserService.selectRoleName(user.getId());
        Object[] array = list.toArray();
        //封装UserInfoVo对象
        UserInfoVo userInfoVo = new UserInfoVo(user.getId(), user.getUsername(),
                user.getAvatar(), user.getNickname(), array);
        return Result.success(userInfoVo).setMessage("获取用户信息成功");
    }
    //获取用户权限菜单
    @GetMapping("/menuList")
    public Result getMenuList(){
        //01-获取当前用户信息，从SecurityContextHolder获取
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication==null){
            return Result.fail().setMessage("认证信息为空");
        }
        //从authentication获取用户信息
        User user = (User) authentication.getPrincipal();
        //02-获取用户的权限列表
        List<Permission> permissionList = user.getPermissionList();
        //03-获取用户的菜单，需要将permission_type为2的按钮类型去除，0根目录，1子目录，按钮类型不需要生成菜单
        permissionList.removeIf(permission -> Objects.equals(permission.getPermissionType(), 2));
        //04-调用RouteTreeUtils生成路由菜单
        List<RouteVo> routeVoList = RouteTreeUtils.buildRouteTree(permissionList, 0);
        return Result.success(routeVoList).setMessage("获取菜单列表成功");
    }
}
